﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using csis.ImmediatorClasses;
using System.IO;

namespace csis.ShellClasses
{
	public class Shell
	{
		public Shell(ShellOptions options)
		{
			if (options == null)
			{
				throw new ArgumentNullException("options");
			}

			this.options = options;
		}

		private ShellOptions options;

		public static bool Execute(ShellOptions options)
		{
			var shell = new Shell(options);
			var success = shell.Run();
			return success;
		}

		public bool Run()
		{
			var success = this.RunInternal();
			if (!success)
			{
				if (this.options.PauseOnErrors || this.options.PauseAfterScript)
				{
					Console.WriteLine("Errors detected. Press any key to continue.");
					Console.ReadKey();
				}
			}
			else if (this.options.PauseAfterScript)
			{
				Console.WriteLine("Script executed. Press any key to continue.");
				Console.ReadKey();
			}
			return success;
		}

		private bool RunInternal()
		{
			if (this.options.UsageErrors.Count != 0)
			{
				this.UsageErrors();
				return false;
			}
			if (this.options.Usage)
			{
				this.Usage();
				return false;
			}
			else if (this.options.UsageExamples)
			{
				this.UsageExamples();
				return true;
			}
			else if (this.options.PreprocessorHelp)
			{
				this.PreprocessorHelp();
				return true;
			}
			else if (this.options.QuickHeaderHelp)
			{
				this.QuickHeaderHelp();
				return true;
			}
			else if (this.options.AutomainHelp)
			{
				this.AutomainHelp();
				return true;
			}
			else if (this.options.ScriptHelpersHelp)
			{
				this.ScriptHelpersHelp();
				return true;
			}
			else
			{
				this.options.ImmediatorOptions.CompilerOptions.CompilerErrorHandler = this.CompilerErrorHandler;
				var success = Immediator.Run(this.options.ImmediatorOptions);
				return success;
			}
		}

		/// <summary>
		/// Displays compiler errors, if any.
		/// </summary>
		private void CompilerErrorHandler(List<CompileError> errors)
		{
			if (errors.Count == 0)
			{
				if (!this.options.NoCompilationSuccessfulMessage)
				{
					Console.WriteLine("Compilation successful");
				}
				return;
			}

			foreach (var error in errors)
			{
				var errorType = error.IsWarning ? "Warning" : "Error";

				if (String.IsNullOrEmpty(error.CompiledFile))
				{
					// file-independent error
					Console.WriteLine("{2} {0}: {1}", error.ErrorCode, error.ErrorMessage, errorType);
				}
				else
				{
					Console.WriteLine(
						"{0} ({1}, {2}) {5} {3}: {4}",
						error.OriginalFile, error.OriginalLine, error.Column, error.ErrorCode, error.ErrorMessage, errorType
					);

					// display the line where the error occurred
					var fileContent = File.ReadAllLines(error.CompiledFile);
					Console.WriteLine(fileContent[error.CompiledLine - 1]);
				}
			}
		}

		private void Usage()
		{
			Console.WriteLine(Properties.Resources.UsageText);
			this.Version();
		}

		private void Version()
		{
			var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
			Console.WriteLine("Assembly Version: " + version.ToString());
		}

		private void UsageErrors()
		{
			foreach (var error in this.options.UsageErrors)
			{
				Console.WriteLine(error);
			}
		}

		private void AutomainHelp()
		{
			Console.WriteLine(Properties.Resources.AutomainExample);
		}

		private void QuickHeaderHelp()
		{
			Console.WriteLine(Properties.Resources.QuickHeader);
		}

		private void UsageExamples()
		{
			Console.WriteLine(Properties.Resources.UsageExamples);
		}

		private void PreprocessorHelp()
		{
			Console.WriteLine(Properties.Resources.PreprocessorHelp);
		}

		private void ScriptHelpersHelp()
		{
			Console.WriteLine(Properties.Resources.ScriptHelpersHelp);
		}
	}
}
